cmake: name a symlinked entry's header the way the CLI does - #46
Merged
Conversation
_rapidproto_output_header resolved symlinks for BOTH of its branches. That is right for the import-relative test -- canonical_entry_name weakly_canonical()s the entry and the include dir before relativizing -- but wrong for the fallback, where the CLI returns the spelling it was given and header_path reduces it with filename(). So an entry reached through a symlink whose name differs from its target's, and resolving under no import dir, had the helper declare aaa.rp.hpp while the CLI wrote alias.rp.hpp. The declared OUTPUT is never produced, so the target regenerates on every build; Ninja does not error, it just re-runs. REALPATH also gives up on the WHOLE path as soon as its last component is missing, while weakly_canonical resolves the longest existing prefix -- so a .proto emitted by another rule, under a symlinked path, disagreed the same way, at any depth of not-yet-created directories (a build tree below macOS's /var -> /private/var makes that ordinary). The helper now walks up to the deepest part that exists, resolves that, and re-attaches the rest, which is what the CLI computes once the file is there. tests/check_generate_names.sh keeps the two rules in step: they are written in different languages and nothing else compares them, which is how they drifted. It runs the real CLI and the real helper over eleven entry shapes and reports which side said what, needing no build or install (the helper is include-safe under `cmake -P`), so the stage costs about a second. Every rule in the helper has a case that fails when it is mutated, which took three tries to get right: a symlinked import dir with a TOP-LEVEL entry cannot distinguish the right answer from the fallback, so that fixture is a directory deep; first-match and import-dir ORDER are invisible with a single -I, so two cases pass overlapping dirs in both orders; the ".proto$" anchor needs a name with ".proto" in the middle; and the resolve-the-existing-prefix rule needs an entry whose parents are absent when the helper predicts and present when the CLI runs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
_rapidproto_output_header resolved symlinks for BOTH of its branches. That is right for the import-relative test -- canonical_entry_name weakly_canonical()s the entry and the include dir before relativizing -- but wrong for the fallback, where the CLI returns the spelling it was given and header_path reduces it with filename().
So an entry reached through a symlink whose name differs from its target's, and resolving under no import dir, had the helper declare aaa.rp.hpp while the CLI wrote alias.rp.hpp. The declared OUTPUT is never produced, so the target regenerates on every build; Ninja does not error, it just re-runs.
REALPATH also gives up on the WHOLE path as soon as its last component is missing, while weakly_canonical resolves the longest existing prefix -- so a .proto emitted by another rule, under a symlinked path, disagreed the same way, at any depth of not-yet-created directories (a build tree below macOS's /var -> /private/var makes that ordinary). The helper now walks up to the deepest part that exists, resolves that, and re-attaches the rest, which is what the CLI computes once the file is there.
tests/check_generate_names.sh keeps the two rules in step: they are written in different languages and nothing else compares them, which is how they drifted. It runs the real CLI and the real helper over eleven entry shapes and reports which side said what, needing no build or install (the helper is include-safe under
cmake -P), so the stage costs about a second.Every rule in the helper has a case that fails when it is mutated, which took three tries to get right: a symlinked import dir with a TOP-LEVEL entry cannot distinguish the right answer from the fallback, so that fixture is a directory deep; first-match and import-dir ORDER are invisible with a single -I, so two cases pass overlapping dirs in both orders; the ".proto$" anchor needs a name with ".proto" in the middle; and the resolve-the-existing-prefix rule needs an entry whose parents are absent when the helper predicts and present when the CLI runs.